﻿using System;
using System.Linq;
using System.Windows;
using Trentacular.SharePoint.Deployment.Data;
using Trentacular.SharePoint.Deployment.Util;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace Trentacular.SharePoint.Deployment.Views
{
    public delegate IEnumerable<T> RetrieveEnumerableAction<T>();

    public abstract class BaseView
    {
        private App _app;
        public App App
        {
            get
            {
                if (_app == null)
                    _app = App.Current;
                return _app;
            }
        }

        public AppData Data { get { return App.Data; } }

        public FrameworkElement Owner { get; private set; }
        
        public BaseView(FrameworkElement owner)
        {
            Owner = owner;
        }

        #region IsDoingWork

        public static DependencyProperty IsDoingWorkProperty;

        public static bool GetIsDoingWork(FrameworkElement element)
        {
            return element.GetThreadSafeValue<bool>(IsDoingWorkProperty);
        }

        public static void SetIsDoingWork(FrameworkElement element, bool value)
        {
            element.SetThreadSafeValue(IsDoingWorkProperty, value);
        }

        public bool IsDoingWork
        {
            get { return Owner.GetThreadSafeValue<bool>(IsDoingWorkProperty); }
            set { Owner.SetThreadSafeValue(IsDoingWorkProperty, value); }
        }

        #endregion

        static BaseView()
        {
            IsDoingWorkProperty = DependencyProperty.RegisterAttached(
                "IsDoingWork",
                typeof(bool),
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
                    delegate(DependencyObject source, DependencyPropertyChangedEventArgs args)
                    {
                        System.Diagnostics.Trace.WriteLine("Callback for IsDoingWork property changed: " + source.GetType().FullName);
                    })
                );
        }

        private object WorkerStateChangeLock = new object();
        protected int NumWorkers { get; set; }
        
        public void DoWorkAsync<T>(Action<T> action, Action<T> callback, T state)
        {
            lock (WorkerStateChangeLock)
            {
                if (!IsDoingWork)
                    IsDoingWork = true;

                NumWorkers++;          
            }

            var marshaler = DelegateMarshaler.Create();
            DelegateMarshaler.QueueOnThreadPoolThread(delegate(T s1)
            {
                try
                {
                    action(s1);
                }
                finally
                {
                    marshaler.Invoke(delegate(T s2)
                    {
                        lock (WorkerStateChangeLock)
                        {
                            NumWorkers--;

                            if (NumWorkers == 0)
                                IsDoingWork = false;
                        }

                        if (callback != null)
                            callback(s2);
                    },
                    s1);
                }
            },
            state);
        }

        public void FillCollectionAsync<T>(ObservableCollection<T> collection, RetrieveEnumerableAction<T> action)
        {
            List<T> results = null;
            DoWorkAsync(delegate(object state)
            {
                results = action().ToList();
            },
            delegate(object state)
            {
                collection.Add(results);
            },
            null);
        }
    }
}
